package com.zenithmind.exam.handler;

import com.zenithmind.common.handler.CommonGlobalExceptionHandler;
import com.zenithmind.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 考试服务全局异常处理器
 * 
 * @author ZenithMind
 * @since 2024-07-01
 */
@Slf4j
@RestControllerAdvice
public class ExamGlobalExceptionHandler extends CommonGlobalExceptionHandler {

    /**
     * 处理认证异常
     */
    @ExceptionHandler(AuthenticationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Result<Void> handleAuthenticationException(AuthenticationException ex) {
        log.error("认证异常: {}", ex.getMessage());
        return Result.fail(401, "认证失败，请重新登录", null);
    }

    /**
     * 处理凭证错误异常
     */
    @ExceptionHandler(BadCredentialsException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Result<Void> handleBadCredentialsException(BadCredentialsException ex) {
        log.error("凭证错误异常: {}", ex.getMessage());
        return Result.fail(401, "用户名或密码错误", null);
    }

    /**
     * 处理权限不足异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Result<String> handleAccessDeniedException(AccessDeniedException ex) {
        log.error("权限不足异常: {}", ex.getMessage());
        return Result.fail(403, "权限不足，无法访问该资源", null);
    }



    /**
     * 处理参数绑定异常
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleBindException(BindException ex) {
        log.error("参数绑定异常: {}", ex.getMessage());
        
        String errorMessage = ex.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(", "));
        
        return Result.fail(400, "参数绑定失败: " + errorMessage, null);
    }

    /**
     * 处理约束违反异常 - @Validated注解
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleConstraintViolationException(ConstraintViolationException ex) {
        log.error("约束违反异常: {}", ex.getMessage());
        
        String errorMessage = ex.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(", "));
        
        return Result.fail(400, "参数校验失败: " + errorMessage, null);
    }

    /**
     * 处理考试相关业务异常
     */
    @ExceptionHandler(ExamBusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleExamBusinessException(ExamBusinessException ex) {
        log.error("考试业务异常: {}", ex.getMessage());
        return Result.fail(ex.getCode(), ex.getMessage(), null);
    }

    /**
     * 处理题目相关业务异常
     */
    @ExceptionHandler(QuestionBusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleQuestionBusinessException(QuestionBusinessException ex) {
        log.error("题目业务异常: {}", ex.getMessage());
        return Result.fail(ex.getCode(), ex.getMessage(), null);
    }

    /**
     * 考试业务异常类
     */
    public static class ExamBusinessException extends RuntimeException {
        private final Integer code;

        public ExamBusinessException(String message) {
            super(message);
            this.code = 400;
        }

        public ExamBusinessException(Integer code, String message) {
            super(message);
            this.code = code;
        }

        public Integer getCode() {
            return code;
        }
    }

    /**
     * 题目业务异常类
     */
    public static class QuestionBusinessException extends RuntimeException {
        private final Integer code;

        public QuestionBusinessException(String message) {
            super(message);
            this.code = 400;
        }

        public QuestionBusinessException(Integer code, String message) {
            super(message);
            this.code = code;
        }

        public Integer getCode() {
            return code;
        }
    }
}
